package com.xw.unification.config;

import com.xw.unification.annotations.ResultMessageMapping;
import com.xw.unification.annotations.ResultMessageMappings;
import com.xw.unification.annotations.SignatureCheckDefinition;
import com.xw.unification.constant.UnificationConstant.RepeatableRequest;
import com.xw.unification.constant.UnificationConstant.SignatureCheckConstant;
import com.xw.unification.enums.ErrorStatusBodyStrategy;
import com.xw.unification.enums.MessagePriority;
import com.xw.unification.enums.SignatureOperation;
import com.xw.unification.enums.SortType;
import com.xw.unification.enums.VersionMatchStrategy;
import com.xw.unification.interfaces.ResultCodeEnumerable;
import com.xw.unification.helper.StringHelper;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.http.MediaType;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.xw.unification.constant.UnificationConstant.DEFAULT_API_VERSION_ENABLE;
import static com.xw.unification.constant.UnificationConstant.DEFAULT_ENABLE;
import static com.xw.unification.constant.UnificationConstant.DEFAULT_UNIFIED_EXCEPTION_ENABLE;
import static com.xw.unification.constant.UnificationConstant.DEFAULT_UNIFIED_RESPONSE_ENABLE;

/**
 * 统一组件配置 properties
 *
 * @author qiwei
 * @date 2023-8-9 21:00:00
 * @since v1.0.0
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "web.unification-config", ignoreUnknownFields = true, ignoreInvalidFields = true)
public class WebUnificationMvcProperties {

    /**
     * 统一配置开关
     */
    private boolean enable = DEFAULT_ENABLE;

    /**
     * API 版本号配置
     */
    private final ApiVersionProperties apiVersion = new ApiVersionProperties();

    /**
     * API 验签配置
     */
    private final SignatureCheckProperties apiSignatureCheck = new SignatureCheckProperties();

    /**
     * API 验签配置
     */
    private final RepeatableRequestProperties requestBodyRepeatableRead = new RepeatableRequestProperties();

    /**
     * 统一响应体配置
     */
    private final UnifiedResponseProperties unifiedResponse = new UnifiedResponseProperties();

    /**
     * 统一异常处理配置
     */
    private final UnifiedExceptionProperties unifiedException = new UnifiedExceptionProperties();


    /**
     * API 版本号配置类
     */
    @Getter
    @Setter
    public static class ApiVersionProperties {

        /**
         * API 版本号配置开关
         */
        private boolean enable = DEFAULT_API_VERSION_ENABLE;

        /**
         * API 版本号匹配策略
         */
        private VersionMatchStrategy versionMatchStrategy = VersionMatchStrategy.STRICT_EQUALS;

    }

    /**
     * 统一响应体配置类
     */
    @Getter
    @Setter
    public static class UnifiedResponseProperties {

        /**
         * 统一响应体配置开关
         */
        private boolean enable = DEFAULT_UNIFIED_RESPONSE_ENABLE;

        private List<String> basePackages = new ArrayList<>();

        /**
         * 统一响应体响应配置
         */
        private UnifiedResponseResult result = new UnifiedResponseResult();

        /**
         * 默认编码类型
         */
        private String defaultCharacterEncoding = "utf-8";

        /**
         * 默认响应文本类型
         */
        private String defaultContentType = MediaType.APPLICATION_JSON_VALUE;

        /**
         * 默认响应文本类型
         */
        private boolean aggressiveConvertContentTypeToJson = false;

    }

    /**
     * 统一异常处理配置类
     */
    @Getter
    @Setter
    public static class UnifiedExceptionProperties {

        /**
         * 统一异常处理配置开关
         */
        private boolean enable = DEFAULT_UNIFIED_EXCEPTION_ENABLE;

    }

    /**
     * 统一验签处理配置类
     */
    @Getter
    @Setter
    public static class SignatureCheckProperties {

        /**
         * 统一异常处理配置开关
         */
        private boolean enable = SignatureCheckConstant.DEFAULT_API_SIGNATURE_ENABLE;

        private boolean globalCheck = SignatureCheckConstant.DEFAULT_GLOBAL_CHECK;

        private List<String> checkPackages = new ArrayList<>();

        private List<String> checkClasses = new ArrayList<>();

        private String charsetName = SignatureCheckConstant.DEFAULT_CHARSET_NAME;

        /**
         * Annotation {@link SignatureCheckDefinition} configurable params
         */

        private boolean hasSignatureKey = SignatureCheckConstant.DEFAULT_HAS_SIGNATURE_KEY;

        private boolean signatureKeyInSort = SignatureCheckConstant.DEFAULT_SIGNATURE_KEY_IN_SORT;

        private String signatureKeyName = SignatureCheckConstant.DEFAULT_SIGNATURE_KEY_NAME;

        private String validationSignatureName = SignatureCheckConstant.DEFAULT_VALIDATION_SIGNATURE_NAME;

        private boolean ignoreEmptyValue = SignatureCheckConstant.DEFAULT_IGNORE_EMPTY_VALUE;

        private String checkErrorEnumName = null;

        private SortType paramNameSort = SignatureCheckConstant.DEFAULT_SIGNATURE_PARAM_NAME_CHECK_SORT;

        private List<SignatureOperation> signatureOperations = new ArrayList<>(
                Arrays.asList(SignatureOperation.MD5, SignatureOperation.UPPER)
        );

    }

    /**
     * 可重读 request body 配置类
     */
    @Getter
    @Setter
    public static class RepeatableRequestProperties {

        /**
         * 统一异常处理配置开关
         */
        private boolean enable = RepeatableRequest.DEFAULT_ENABLE;

        /**
         * 统一异常处理配置开关
         */
        private final RewriteInterceptorProperties rewriteInterceptor = new RewriteInterceptorProperties();

        /**
         * 允许 Content-Type 为 null
         */
        private boolean allowNoContentType = RepeatableRequest.DEFAULT_ALLOW_NO_CONTENT_TYPE;

        /**
         * 允许重复获取 ServletInputStream 的 Content-Type
         * <p>
         *     <b>不配置时默认为 [ application/json, text/plain ]</b>
         * </p>
         */
        private List<String> repeatableContentTypes = new ArrayList<>(Arrays.asList(
                MediaType.APPLICATION_JSON_VALUE,
                MediaType.TEXT_PLAIN_VALUE
        ));

        /**
         * 最大允许的 Content-Length 的长度
         */
        private long maxContentLength = Integer.MAX_VALUE;

        /**
         * Content-Length 超出 {@link Integer#MAX_VALUE} 时是否跳过处理
         * <ul>
         *     <li>
         *         如果为 true, 且 Content-Length > {@link Integer#MAX_VALUE} 时,
         *         放弃重写 request, request 不可重复读
         *     </li>
         *     <li>如果为 false, 则继续尝试重写 request</li>
         * </ul>
         * @deprecated 不建议设置该属性, 建议通过 {@link RepeatableRequestProperties#maxContentLength}
         *             约束 request body 的长度
         */
        @Deprecated
        private boolean skipIfContentLengthOverInt = RepeatableRequest.DEFAULT_SKIP_IF_CONTENT_LENGTH_OVER_INT;

        @Deprecated
        private String requestBodyCacheFolderPath = null;
    }

    /**
     * 统一响应体响应配置类
     */
    @Getter
    @Setter
    public static class UnifiedResponseResult {

        /**
         * 自定义响应码枚举类
         */
        private Class<?> enumClass = null;

        /**
         * 默认成功响应枚举
         */
        private String defaultSuccessEnum = null;

        /**
         * 默认失败响应枚举
         */
        private String defaultErrorEnum = null;

        /**
         * HttpStatus 异常 code - 自定义枚举 映射
         * <p>
         *     error code >= {@link org.springframework.http.HttpStatus#BAD_REQUEST}.value() 时认定为 HttpStatus 异常 code
         * </p>
         */
        private Map<Integer, String> errorStatusEnumMapping = new HashMap<>();

        /**
         * HttpStatus 异常 code 响应体 body 的内容策略
         * <p>
         *     error code >= {@link org.springframework.http.HttpStatus#BAD_REQUEST}.value() 时认定为 HttpStatus 异常 code
         * </p>
         */
        private ErrorStatusBodyStrategy errorStatusBodyStrategy = ErrorStatusBodyStrategy.NONE;

        /**
         * 自定义枚举响应码全局映射 Message 映射,
         *
         * <p>
         *     优先级低于
         *     {@link ResultMessageMapping}
         *     和
         *     {@link ResultMessageMappings}
         * </p>
         * <p>
         *     ResultMessageMapping 优先级高于 ResultMessageMappings
         * </p>
         */
        private Map<Integer, String> resultMessageGlobalMapping = new HashMap<>();

        /**
         * 默认失败响应枚举
         */
        private MessagePriority resultMessagePriorityWhenUnifiedException = MessagePriority.EXCEPTION;

        public ResultCodeEnumerable getEnumByClass(String enumName) {
            if (StringHelper.hasText(enumName) && getEnumClass() != null && Enum.class.isAssignableFrom(getEnumClass())
                    && ResultCodeEnumerable.class.isAssignableFrom(getEnumClass())) {
                try {
                    return (ResultCodeEnumerable) Enum.valueOf((Class) getEnumClass(), enumName);
                } catch (Exception e) {
                    return null;
                }
            }
            return null;
        }

    }

    /**
     * 可重读 request 重写拦截器
     */
    @Getter
    @Setter
    public static class RewriteInterceptorProperties {

        /**
         * 是否开启重写拦截器
         */
        private boolean enable = false;

        /**
         * 重写拦截器路径配置
         */
        private List<String> interceptPaths = new ArrayList<>();

    }
}
